//
// Created by lz on 2021/2/17.
//

#ifndef MYWEBLIB_NET_BUFFER_H_
#define MYWEBLIB_NET_BUFFER_H_
#include "base/copyable.h"
#include "base/StringPiece.h"
#include "base/Types.h"

#include "net/Endian.h"

#include <algorithm>
#include <vector>
#include <assert.h>
#include <string.h>

namespace lzweb
{
	namespace net
	{
		/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
		///
		/// @code
		/// +-------------------+------------------+------------------+
		/// | prependable bytes |  readable bytes  |  writable bytes  |
		/// |                   |     (CONTENT)    |                  |
		/// +-------------------+------------------+------------------+
		/// |                   |                  |                  |
		/// 0      <=      readerIndex   <=   writerIndex    <=     size
		/// @endcode

		class Buffer : public copyable
		{
		 public:
			static  const size_t kCheapPrepend = 8;
			static  const size_t kInitialSize = 1024;

			explicit Buffer(size_t initialSize = kInitialSize)
			:buffer_(kCheapPrepend + initialSize),
			readerIndex_(kCheapPrepend),
			writerIndex_(kCheapPrepend)
			{
				assert(readableBytes() == 0);
				assert(writableBytes() == 0);
				assert(prependableBytes() == kCheapPrepend);
			}

			// implicit copy-ctor, move-ctor, dtor and assignment are fine
			// NOTE: implicit move-ctor is added in g++ 4.6

			void swap(Buffer& rhs)
			{
				buffer_.swap(rhs.buffer_);
				std::swap(readerIndex_,rhs.readerIndex_);
				std::swap(writerIndex_,rhs.writerIndex_);
			}

			size_t readableBytes() const
			{ return writerIndex_ - readerIndex_; }

			size_t writableBytes() const
			{ return buffer_.size() - writerIndex_; }

			size_t prependableBytes() const
			{ return readerIndex_; }

			// 返回缓冲区指向第一个字符的指针
			const char* peek() const
			{ return begin() + readerIndex_; }

			const char* findCRLF() const
			{
				/// FIXME: replace with memmem()?
				const char* crlf = std::search(peek(),beginWrite(),kCRLF,kCRLF +2);
				return crlf == beginWrite() ? nullptr : crlf;
			}

			const char* findCRLF(const char* start) const
			{
				assert(peek()<=start);
				assert(start <= beginWrite());
				///FIXME: replace with memmem() ?
				const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
				return crlf == beginWrite() ? NULL : crlf;
			}

			// EOL -> end of line
			const char* findEOL() const
			{
				const void * eol = memchr(peek(), '\n', readableBytes());
				return static_cast<const char*>(eol);
			}

			const char* findEOL(const char* start) const
			{
				assert(peek() <= start);
				assert( start <= beginWrite());
				const void * eol = memchr(start, '\n', readableBytes());
				return static_cast<const char*>(eol);
			}

			//retrieve -> 检索,恢复

			// retrieve returns void, to prevent
			// string str(retrieve(readableBytes()), readableBytes());
			// the evaluation of two functions are unspecified
			void retrieve(size_t len)
			{
				assert(len <= readableBytes());
				if(len < readableBytes())
				{
					readerIndex_ += len;
				}
				else
				{
					retrieveAll();
				}
			}

			void retrieveUntil(const char* end)
			{
				assert(peek() <= end);
				assert(end <= beginWrite());
				retrieve(end - peek());
			}

			void retrieveInt64()
			{
				retrieve(sizeof(int64_t));
			}

			void retrieveInt32()
			{
				retrieve(sizeof(int32_t));
			}

			void retrieveInt16()
			{
				retrieve(sizeof(int16_t));
			}

			void retrieveInt8()
			{
				retrieve(sizeof(int8_t));
			}



			void retrieveAll()
			{
				readerIndex_ = kCheapPrepend;
				writerIndex_ = kCheapPrepend;
			}

			// 读取所有数据，存在string并返回
			string retrieveAllAsString()
			{
				return retrieveAsString(readableBytes());
			}

			// 读取 len 长度的数据，并返回string
			string retrieveAsString(size_t len)
			{
				assert(len <= readableBytes());
				string result(peek(), len);
				retrieve(len);
				return result;
			}

			//返回包含数据的StringPiece，StringPiece仅代理数据，不管理生命周期
			StringPiece toStringPiece() const
			{
				return StringPiece(peek(), static_cast<int>(readableBytes()));
			}

			void append(const StringPiece& str)
			{
				append(str.data(),str.size());
			}

			void append( const char* data, size_t len)
			{
				ensureWritableBytes(len);
				std::copy(data,data+len,beginWrite());
				hasWritten(len);

			}

			void append(const void* /*restrict*/ data, size_t len)
			{
				append(static_cast<const char*>(data), len);
			}

			void ensureWritableBytes(size_t len)
			{
				if(writableBytes() < len)
				{
					makeSpace( len);
				}
				assert(writableBytes() >= len);
			}

			char* beginWrite()
			{ return begin() + writerIndex_; }

			const char* beginWrite() const
			{ return begin() + writerIndex_; }

			// 该函数用于写入数据后，调整writerIndex_位置
			void hasWritten(size_t len)
			{
				assert(len <= writableBytes());
				writerIndex_ += len;
			}

			void unwrite(size_t len)
			{
				assert(len <= readableBytes());
				writerIndex_ -= len;
			}

			///
			/// Append int64_t using network endian
			///
			void appendInt64(int64_t x)
			{
				int64_t be64 = sockets::hostToNetwork64(x);
				append(&be64, sizeof be64);
			}

			///
			/// Append int32_t using network endian
			///
			void appendInt32(int32_t x)
			{
				int32_t be32 = sockets::hostToNetwork32(x);
				append(&be32, sizeof be32);
			}

			void appendInt16(int16_t x)
			{
				int16_t be16 = sockets::hostToNetwork16(x);
				append(&be16, sizeof be16);
			}

			void appendInt8(int8_t x)
			{
				append(&x, sizeof x);
			}


			/// peek function just gets data, and retrieve function just move the readerIndex_(while legal)
			/// so peek + retrieve = read function

			///
			/// Read int64_t from network endian
			///
			/// Require: buf->readableBytes() >= sizeof(int32_t)
			int64_t readInt64()
			{
				int64_t result = peekInt64();
				retrieveInt64();
				return result;
			}

			///
			/// Read int32_t from network endian
			///
			/// Require: buf->readableBytes() >= sizeof(int32_t)
			int32_t readInt32()
			{
				int32_t result = peekInt32();
				retrieveInt32();
				return result;
			}

			int16_t readInt16()
			{
				int16_t result = peekInt16();
				retrieveInt16();
				return result;
			}

			int8_t readInt8()
			{
				int8_t result = peekInt8();
				retrieveInt8();
				return result;
			}





			// peek -> (计算机) 读取数据

			///
			/// Peek int64_t from network endian
			///
			/// Require: buf->readableBytes() >= sizeof(int64_t)
			int64_t peekInt64() const
			{
				assert(readableBytes() >= sizeof(int64_t));
				int64_t be64 = 0;
				::memcpy(&be64, peek(), sizeof be64);
				return sockets::networkToHost64(be64);
			}
			///
			/// Peek int32_t from network endian
			///
			/// Require: buf->readableBytes() >= sizeof(int32_t)
			int32_t peekInt32() const
			{
				assert(readableBytes() >= sizeof(int32_t));
				int32_t be32 = 0;
				::memcpy(&be32, peek(), sizeof be32);
				return sockets::networkToHost32(be32);
			}

			int16_t peekInt16() const
			{
				assert(readableBytes() >= sizeof(int16_t));
				int16_t be16 = 0;
				::memcpy(&be16, peek(), sizeof be16);
				return sockets::networkToHost16(be16);
			}
			// 字节序问题中高位和低位是按字节来读的，因此单字节不存在高位低位问题
			int8_t peekInt8() const
			{
				assert(readableBytes() >= sizeof(int8_t));
				int8_t x = *peek();
				return x;
			}

			///
			/// Prepend int64_t using network endian
			///
			void prependInt64(int64_t x)
			{
				int64_t be64 = sockets::hostToNetwork64(x);
				prepend(&be64, sizeof be64);
			}

			///
			/// Prepend int32_t using network endian
			///
			void prependInt32(int32_t x)
			{
				int32_t be32 = sockets::hostToNetwork32(x);
				prepend(&be32, sizeof be32);
			}

			void prependInt16(int16_t x)
			{
				int16_t be16 = sockets::hostToNetwork16(x);
				prepend(&be16, sizeof be16);
			}

			void prependInt8(int8_t x)
			{
				prepend(&x, sizeof x);
			}

			//在数据的前面加 len 字符 ， len <= readerIndex_;
			void prepend(const void* /*restrict*/ data, size_t len)
			{
				assert(len <= prependableBytes());
				readerIndex_ -= len;
				const char* d = static_cast<const char*>(data);
				std::copy(d, d+len, begin()+readerIndex_);
			}

			void shrink(size_t reserve)
			{
				Buffer other;
				other.ensureWritableBytes(readableBytes() + reserve);
				other.append(toStringPiece());
				swap(other);
			}

			size_t internalCapacity() const
			{
				return buffer_.capacity();
			}

			/// Read data directly into buffer.
			///
			/// It may implement with readv(2)
			/// @return result of read(2), @c errno is saved
			ssize_t readFd( int fd, int* savedErrno);



		 private:
			char* begin()
			{return &*buffer_.begin();}

			const char* begin() const     //重载函数需要不同的参数，而const使隐含的this指针参数类型变为const
			{return &*buffer_.begin();}

			void makeSpace(size_t len)
			{
				if(writableBytes() + prependableBytes() < len + kCheapPrepend)
				{
					buffer_.resize(writerIndex_ + len);
				}
				else
				{
					// move readable data to the front, make space inside buffer
					assert(kCheapPrepend < readerIndex_);
					size_t readable = readableBytes();
					std::copy(begin() + readerIndex_,
							  begin() + writerIndex_,
							  begin() + kCheapPrepend);

					readerIndex_ = kCheapPrepend;
					writerIndex_ = readerIndex_ + readable;
					assert(readable == readableBytes());
				}
			}


		 private:
			std::vector<char> buffer_;
			size_t readerIndex_;
			size_t writerIndex_;     // size_t -> unsigned long

			// 在文本处理中, CR, LF, CR/LF 是不同操作系统上使用的换行符
			// CR -> carriage return -> 回车; LF -> line feed -> 换行
			static const char kCRLF[]; //此处为static const成员， 在后面给出了定义后长度固定，因此此处可以不指明长度？

		};
	} // namespace net
}//namespace lzweb

#endif //MYWEBLIB_NET_BUFFER_H_
